package cn.smxy.user.service.impl;

import cn.smxy.client.CollegeClient;
import cn.smxy.client.CommentClient;
import cn.smxy.client.PlantClient;
import cn.smxy.constant.RegexConstant;
import cn.smxy.constant.UserConstant;
import cn.smxy.excel.UserExcel;
import cn.smxy.param.*;
import cn.smxy.pojo.Campus;
import cn.smxy.pojo.College;
import cn.smxy.pojo.User;
import cn.smxy.user.mapper.CampusMapper;
import cn.smxy.user.mapper.UserMapper;
import cn.smxy.user.service.UserService;
import cn.smxy.util.MD5Util;
import cn.smxy.util.R;
import cn.smxy.util.VerifyCodeUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.MailSendException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.net.MalformedURLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CampusMapper campusMapper;
    @Autowired
    private CollegeClient collegeClient;
    @Autowired
    private PlantClient plantClient;
    @Autowired
    private CommentClient commentClient;
    @Value("${spring.mail.username}")
    private String sender;
    @Autowired
    private JavaMailSender mailSender; //自动装配邮箱接口


    /**
     * 检查是否存在重复邮箱
     *
     * @param userEmail
     * @return
     */
    @Override
    public Long checkEmail(String userEmail) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", userEmail);
        Long count = userMapper.selectCount(queryWrapper);
        return count;
    }

    /**
     * 删除用户
     * 1.删除用户对应的作品
     * 2.校园认证
     * 3.校园作品
     * 4.评论
     * 5.植物作品
     *
     * @param userId
     * @return
     */
    @Override
    public R delete(Long userId) {
        int rows = userMapper.deleteById(userId);
        if(rows == 0) {
            return R.fail("删除失败");
        }
        QueryWrapper<Campus> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId);
        campusMapper.delete(queryWrapper);
        collegeClient.removeByUserId(userId);
        plantClient.removeByUserId(userId);
        commentClient.removeById(userId);

        return R.ok("删除成功");
    }

    /**
     * 用户绑定邮箱
     *
     * @param loginEmailParam
     * @return
     */
    @Override
    public R bindEmail(LoginEmailParam loginEmailParam) {
        String userEmail = loginEmailParam.getUserEmail();
        String emailCode = loginEmailParam.getEmailCode();
        Jedis jedis = new Jedis("47.115.227.121", 6379);
        String verCode = jedis.get(userEmail + 0);
        if (verCode != null && verCode.equals(emailCode)) {
            User user = new User();
            user.setUserPhoto(null);
            user.setUserRole(null);
            user.setCreateTime(null);
            user.setUserId(loginEmailParam.getUserId());
            user.setEmail(loginEmailParam.getUserEmail());
            int rows = userMapper.updateById(user);
            if (rows > 0) {
                log.info("UserServiceImpl.bindEmail业务结束，结果为:{}","绑定成功");
                return R.ok("绑定成功");
            } else {
                log.info("UserServiceImpl.bindEmail业务结束，结果为:{}","绑定失败");
                return R.fail("绑定失败");
            }

        }
        log.info("UserServiceImpl.bindEmail业务结束，结果为:{}", "验证码错误");
        return R.fail("验证码错误");
    }

    /**
     * 用户邮箱登录
     *
     * @param loginEmailParam
     * @return
     */
    @Override
    public R loginEmail(LoginEmailParam loginEmailParam) {
        String userEmail = loginEmailParam.getUserEmail();
        String emailCode = loginEmailParam.getEmailCode();
        Jedis jedis = new Jedis("47.115.227.121", 6379);
        String verCode = jedis.get(userEmail + 1);
        if (verCode != null && verCode.equals(emailCode)) {
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("email", userEmail);
            User user = userMapper.selectOne(queryWrapper);
            long currentTime = System.currentTimeMillis() + 60 * 60 * 1000 * 3; // 3小时有效时间
            String token = JWT.create()
                    .withAudience(String.valueOf(user.getUserId()))
                    .withSubject("token")
                    .withExpiresAt(new Date(currentTime))
                    .sign(Algorithm.HMAC256(user.getUserPassword()));
            user.setUserPassword(null);
            Map<String, Object> map = new HashMap<>();
            map.put("accessToken", token);
            map.put("user", user);
            jedis.set(token, String.valueOf(user.getUserId()));
            jedis.expire(token, UserConstant.TOKEN_EXPIRE_TIME);
            jedis.close();
            return R.ok("登录成功", map);
        }
        jedis.close();
        return R.fail("邮箱验证码错误");
    }

    /**
     * 发送验证码，并保存redis
     *
     * @param emailParam
     * @return
     */
    @Override
    public R toEmail(EmailParam emailParam) {
        // 拆分参数
        String userEmail = emailParam.getUserEmail();
        int tag = emailParam.getTag();

        SimpleMailMessage message = new SimpleMailMessage();  //简单的邮件类
        String verCode = VerifyCodeUtil.generateCode(); // 生成随机的4位数验证码
        message.setFrom(sender);
        message.setTo(userEmail);
        message.setSubject("【Share Plant Image Library】您本次的验证码是");
        message.setText("尊敬的用户,您好:\n"
                + "\n本次请求的邮件验证码为:\n" + verCode + "\n本验证码 5 分钟内效，请及时输入。（请勿泄露此验证码）\n"
                + "\n如非本人操作，请忽略该邮件。\n(这是一封通过自动发送的邮件，请不要直接回复）");
        try {
            log.info("UserServiceImpl.toEmail业务，正在发送邮件...");
            mailSender.send(message);
            Jedis jedis = new Jedis("47.115.227.121", 6379);
            jedis.set(userEmail + tag, verCode);
            jedis.expire(userEmail + tag, UserConstant.EMAIL_TIME);
            jedis.close();
            return R.ok("发送成功");
        } catch (MailSendException e) {
            System.out.println(e.getMessage());
            return R.fail("目标邮箱不存在");
        } catch (Exception e) {
            return R.fail("文本邮件发送异常");
        }
    }

    /**
     * 获取用户名称
     *
     * @param userId
     * @return
     */
    @Override
    public User getUserName(Long userId) {
        User user = new User();
        if (userId == 0) {
            user.setUserName("管理员");
            user.setUserPhoto(UserConstant.ADMIN_PHOTO);
        } else {
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("user_name", "user_photo", "create_time");
            queryWrapper.eq("user_id", userId);
            user = userMapper.selectOne(queryWrapper);
        }
        log.info("UserServiceImpl.getUserName业务结束，结果为:{}", user);
        return user;
    }

    /**
     * 用户退出登录
     *
     * @param token
     * @return
     */
    @Override
    public R logout(String token) {
        Jedis jedis = new Jedis("47.115.227.121", 6379);
        jedis.del(token);
        jedis.close();
        return R.ok("退出成功");
    }

    /**
     * 获取用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public R info(Long userId) {
        User user = baseMapper.selectById(userId);
        user.setUserPassword(null);
        log.info("UserServiceImpl.info业务结束，结果为:{}", "");
        return R.ok(user);
    }

    /**
     * 模糊分页查询用户名
     *
     * @param userSearchParam
     * @return
     */
    @Override
    public R search(UserSearchParam userSearchParam) {
        // 参数拆分
        String userName = userSearchParam.getSearch();
        int currentPage = userSearchParam.getCurrentPage();
        int pageSize = userSearchParam.getPageSize();
        // 条件封装
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (userName != null) {
            queryWrapper.like("user_name", userName);
        }
        IPage<User> page = new Page<>(currentPage, pageSize);
        page = this.page(page, queryWrapper);
        // 结果封装
        long total = page.getTotal();
        List<User> records = page.getRecords();
        R ok = R.ok("查询成功", records, total);
        log.info("UserServiceImpl.search业务结束，结果为:{}", ok);
        return ok;
    }

    /**
     * excel批量导出
     * 1.将User转换成UserExcel，更适合展示
     *
     * @return
     */
    @Override
    public List<UserExcel> getAll() throws MalformedURLException {
        List<User> list = this.list();
        List<UserExcel> result = new ArrayList<>();
        for (User user : list) {
            Long collegeId = user.getCollegeId();
            if (collegeId == null) {
                result.add(new UserExcel(user, null));
            } else {
                R r = collegeClient.detail(new CollegeDetailParam(collegeId));
                ObjectMapper mapper = new ObjectMapper();
                College college = mapper.convertValue(r.getData(), College.class);
                result.add(new UserExcel(user, college.getCollegeName()));
            }
        }
        return result;
    }

    /**
     * excel批量导入
     * 1.用户密码加盐加密
     * 2.批量添加数据库
     *
     * @param list
     * @return
     */
    @Override
    public void saveExcel(List<User> list) {
        for (User user : list) {
            String newPwd = MD5Util.encode(UserConstant.USER_SLAT + user.getUserPassword());
            user.setUserPassword(newPwd);
        }
        this.saveBatch(list);
    }

    /**
     * 返回用户基本信息
     * 用户名 用户头像 高校id
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public User basic(Long userId) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_name", "user_photo", "college_id");
        queryWrapper.eq("user_id", userId);
        User user = userMapper.selectOne(queryWrapper);
        return user;
    }

    /**
     * 修改用户信息
     * 1.检查密码，如果与数据库一致 不需要加密，证明密码没有修改
     * 2.密码不同，已经修改，新密码加密
     * 3.数据库修改
     *
     * @param user 用户实体类
     * @return
     */
    @Override
    public R update(User user) {
        // 检查密码，如果与数据库一致 不需要加密，证明密码没有修改
        if (user.getUserPassword() != null && !user.getUserPassword().equals("")) {
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", user.getUserId());
            queryWrapper.eq("user_password", user.getUserPassword());
            Long total = userMapper.selectCount(queryWrapper);
            if (total == 0) {
                // 密码不同，已经修改，新密码加密
                user.setUserPassword(MD5Util.encode(UserConstant.USER_SLAT + user.getUserPassword()));
            }
        }
        // 数据库修改
        int rows = userMapper.updateById(user);
        if (rows == 0) {
            return R.fail("用户修改失败");
        }
        return R.ok("用户修改成功");
    }

    /**
     * 用户登录
     * 1.用户密码加密
     * 2.比对数据库账号密码
     * 3.返回用户完整对象(为保护用户密码安全不返回密码)
     *
     * @param loginAccountParam 用户登录参数，账号密码
     * @return 用户完整对象
     */
    @Override
    public R loginAccount(LoginAccountParam loginAccountParam) {
        // 用户密码加密
        String newPwd = MD5Util.encode(UserConstant.USER_SLAT + loginAccountParam.getUserPassword());
        // 条件封装
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", loginAccountParam.getUserAccount());
        queryWrapper.eq("user_password", newPwd);
        // 比对数据库账号密码
        User user = userMapper.selectOne(queryWrapper);
        if (user == null) {
            log.info("UserServiceImpl.loginAccount业务结束，结果为:{}", "登录失败，用户名或密码错误");
            return R.fail("用户名或密码错误");
        }
        log.info("UserServiceImpl.loginAccount业务结束，结果为:{}", "登录成功");

        long currentTime = System.currentTimeMillis() + 60 * 60 * 1000 * 3; // 3小时有效时间
        String token = JWT.create()
                .withAudience(String.valueOf(user.getUserId()))
                .withSubject("token")
                .withExpiresAt(new Date(currentTime))
                .sign(Algorithm.HMAC256(user.getUserPassword()));
        user.setUserPassword(null);
        Map<String, Object> map = new HashMap<>();
        map.put("accessToken", token);
        map.put("user", user);
        Jedis jedis = new Jedis("192.168.205.130", 6379);
        jedis.set(token, String.valueOf(user.getUserId()));
        jedis.expire(token, UserConstant.TOKEN_EXPIRE_TIME);
        jedis.close();

        return R.ok("登录成功", map);
    }

    /**
     * 用户注册
     * 1.正则校验账号是否符合规则
     * 2.数据库查询是否存在相同账号
     * 3.密码加密加盐
     * 4.设置用户初始值
     * 5.数据插入数据库
     * 6.返回结果封装
     *
     * @param user 用户实体类
     * @return 结果封装
     */
    @Override
    public R register(User user) {
        // 正则校验
        String userAccount = user.getUserAccount();
        Pattern pattern = Pattern.compile(RegexConstant.USER_ACCOUNT);
        Matcher matcher = pattern.matcher(userAccount);
        if (!matcher.matches()) {
            log.info("UserServiceImpl.register业务结束，结果为:{}", "正则校验，用户账号格式错误");
            return R.fail("用户账号格式错误");
        }
        // 数据库查重
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", userAccount);
        Long total = userMapper.selectCount(queryWrapper);
        if (total > 0) {
            log.info("UserServiceImpl.register业务结束，结果为:{}", "数据库查重，账号已存在，不可使用");
            return R.fail("账号已存在，不可使用");
        }
        // 密码加密加盐
        String newPwd = MD5Util.encode(UserConstant.USER_SLAT + user.getUserPassword());
        user.setUserPassword(newPwd);
        // 设置用户初始值
        user.setCreateTime(System.currentTimeMillis());
        if (user.getUserPhoto() == null || user.getUserPhoto().equals("")) {
            user.setUserPhoto(UserConstant.USER_PHOTO);
        }
        user.setUserRole(UserConstant.ROLE_USER);
        // 插入数据库，返回结果封装
        int rows = userMapper.insert(user);
        if (rows == 0) {
            log.info("UserServiceImpl.register业务结束，结果为:{}", "数据库插入失败，注册失败");
            return R.fail("注册失败");
        }
        log.info("UserServiceImpl.register业务结束，结果为:{}", "注册成功");
        return R.ok("注册成功");
    }

    /**
     * 校验用户账号
     * 1.数据库查询是否存在相同账号
     * 2.返回结果封装
     *
     * @param userCheckParam 用户账号
     * @return 结果封装
     */
    @Override
    public R check(UserCheckParam userCheckParam) {
        String userAccount = userCheckParam.getUserAccount();

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", userAccount);
        Long total = userMapper.selectCount(queryWrapper);
        if (total > 0) {
            log.info("UserServiceImpl.check业务结束，结果为:{}", "用户账号已存在，不可使用");
            return R.fail("账号已存在，不可使用");
        }
        log.info("UserServiceImpl.check业务结束，结果为:{}", "账号不存在，可以使用");
        return R.ok("账号不存在，可以使用");
    }
}
